import java.util.ArrayList;
import java.util.Calendar;

import processing.core.PApplet;
import processing.core.PConstants;

import controlP5.ControlP5;


public class HeatView extends View {
	ControlP5 ControlP5;
	
	private int[][][] DATA;	//[month][day][hour]
	private ArrayList<Integer> colors;
	private int defaultColor;
	
	private int boxSize = 7;
	
	private int minVal;
	private int maxVal;
	private int totalVals = 0;
	
	private int year;	// = 0 when all years (05-09)
	
	controlP5.Button B_Add, B_Remove, 
						B_Year05, B_Year06, B_Year07, B_Year08, B_Year09;
	
	
	public HeatView(int _x1, int _y1, int _x2, int _y2, int yr) {
		x1 = _x1;
		y1 = _y1;
		x2 = _x2;
		y2 = _y2;
		
		year = yr;
		
		minVal = 0;
		DATA = new int[12][7][24];
		colors = new ArrayList<Integer>();
		defaultColor = GLOBAL.colorMenu;
		
		initColors();
		setup();
		
		if(year == 0 || year == 2000)
			parseAllData();
		else
			parseData(year);
	}
	
	private void setup() {
		ControlP5 = new ControlP5(GLOBAL.processing);
			ControlP5.setAutoDraw(false);
			
		B_Add = ControlP5.addButton("vw_add", 0, x1+50, y1+500, 25, 25);
	}
	
	private void parseData(int yr) {
		Calendar cal = Calendar.getInstance();
		String[] rows = getRow(yr);
		
		for(int x=0; x<rows.length; ++x) {
			String[] columns = PApplet.split(rows[x], "-");

				int month 	= Integer.parseInt(columns[0]);
				int day 	= Integer.parseInt(columns[1]);
				int hour 	= Integer.parseInt(columns[2]);
				int value 	= Integer.parseInt(columns[3]);
				
				cal.set(yr, month, day);
				int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);

				DATA[month-1][dayOfWeek-1][hour] += value;	
				totalVals += value;
		}
		
		findMax();
	}
	
	private void parseAllData() {
		for(int x=5; x<10; ++x) {
			parseData(2000+x);
		}
	}
	
	private String[] getRow(int yr) {
		switch(yr) {
		case 2005: return GLOBAL.heatRow2005;
		case 2006: return GLOBAL.heatRow2006;
		case 2007: return GLOBAL.heatRow2007;
		case 2008: return GLOBAL.heatRow2008;
		case 2009: return GLOBAL.heatRow2009;
		}
		
		return GLOBAL.heatRow2005;
	}
	/*
	private void testData() {
		int value = 2;
		for(int x=0; x<12; ++x) {
			for(int y=0; y<7; ++y) {
				for(int z=0; z<24; ++z)  {
					DATA[x][y][z] = value;//(int) GLOBAL.processing.random(value);
					value+=20;
				}
				value = 2;
			}
		}
	}
	*/
	
	public void resize(int _x1, int _y1, int _x2, int _y2) {
		x1 = _x1;
		y1 = _y1;
		x2 = _x2;
		y2 = _y2;
		
		width = x2 - x1;
		height = y2 - y1;
	}
	
	public void draw() {
		GLOBAL.processing.fill(0);
		GLOBAL.processing.rect(x1, y1, x2, y2);
		
		drawMonths();
		drawLabels();
		drawData();
		
		GLOBAL.processing.image(GLOBAL.HUE, x1+10, y1+292);
	}
	
	private void drawData() {
		int xOffset = x1+40;
		int yOffset = y1+40;
		
		for(int x=0; x<12; ++x) {	
			for(int y=0; y<7; ++y) {		
				for(int z=0; z<24; ++z)  {					
					new Box(xOffset, yOffset, boxSize, 
							getColor(DATA[x][y][z]), DATA[x][y][z],
							getDateString(x, y, z), ((x1+x2)/2), y1+270)
								.draw();		
					yOffset += boxSize+1;
				}
				//New Day => Reset yOffset & increment xOffset
				xOffset += boxSize+1;
				yOffset = y1+40;
			}
			//New Year => increment xOffset a bit extra
			xOffset += boxSize+1;
		}
	}//end Draw Data
	
	private void drawMonths() {
		GLOBAL.processing.fill(255);
		GLOBAL.processing.textSize(12);
		GLOBAL.processing.text("Jan", x1+58, y1+245);
		GLOBAL.processing.text("Feb", x1+121, y1+245);
		GLOBAL.processing.text("Mar", x1+184, y1+245);
		GLOBAL.processing.text("Apr", x1+248, y1+245);
		GLOBAL.processing.text("May", x1+312, y1+245);
		GLOBAL.processing.text("Jun", x1+378, y1+245);
		GLOBAL.processing.text("Jul", x1+444, y1+245);
		GLOBAL.processing.text("Aug", x1+502, y1+245);
		GLOBAL.processing.text("Sep", x1+568, y1+245);
		GLOBAL.processing.text("Oct", x1+634, y1+245);
		GLOBAL.processing.text("Nov", x1+696, y1+245);
		GLOBAL.processing.text("Dec", x1+758, y1+245);
		
		GLOBAL.processing.textSize(16);
		GLOBAL.processing.textAlign(PConstants.RIGHT);
		GLOBAL.processing.text(getYearString(), x2-50, y1+25);
	}
	
	private void drawLabels() {
		GLOBAL.processing.fill(255);
		GLOBAL.processing.stroke(120);//GLOBAL.colorTabMouseOver);
		GLOBAL.processing.textAlign(PConstants.LEFT);
		GLOBAL.processing.textFont(GLOBAL.fontSmall);
		
		GLOBAL.processing.text("12am", x1+8, y1+46);
		GLOBAL.processing.line(x1+34, y1+43, x2-40, y1+43);
		
		GLOBAL.processing.text("6am", x1+8, y1+94);
		GLOBAL.processing.line(x1+34, y1+91, x2-40, y1+91);
		
		GLOBAL.processing.text("12pm", x1+8, y1+142);
		GLOBAL.processing.line(x1+34, y1+139, x2-40, y1+139);
		
		GLOBAL.processing.text("6pm", x1+8, y1+190);
		GLOBAL.processing.line(x1+34, y1+187, x2-40, y1+187);
		
		GLOBAL.processing.text("11pm", x1+8, y1+231);
		GLOBAL.processing.line(x1+34, y1+227, x2-40, y1+227);
		
		GLOBAL.processing.text("Sun", x1+34, y1+30);
		GLOBAL.processing.line(x1+43, y1+32, x1+43, y1+38);
		
		GLOBAL.processing.text("Sat", x1+82, y1+30);
		GLOBAL.processing.line(x1+91, y1+32, x1+91, y1+38);
		
		GLOBAL.processing.text("" + 0, x1+10, y1+290);
		GLOBAL.processing.text("" + (maxVal/2), x1+82, y1+290);
		GLOBAL.processing.text("" + maxVal, x1+173, y1+290);
		
		//Draw black rectangles for where data is
		//	For hiding axis labels so they don't overlap data
		//		(Faster than drawing "mini" axis lines)
		GLOBAL.processing.fill(0);
		GLOBAL.processing.noStroke();
		
		int xVal=40;
		for(int x=0; x<12; ++x) {
			GLOBAL.processing.rect(x1+xVal, y1+40, 55, 190);
			xVal += 64;
		}
		
		GLOBAL.loadDefaultFont();
	}
	
	private void initColors() {
		colors.add(newColor(220, 231, 205));
		colors.add(newColor(210, 226, 187)); //Greens
		colors.add(newColor(196, 217, 165));
		colors.add(newColor(186, 212, 148));
		colors.add(newColor(175, 206, 131));
		colors.add(newColor(158, 193, 109));
		colors.add(newColor(148, 189, 89));
		colors.add(newColor(127, 181, 57));
		colors.add(newColor(255, 206, 113)); //Yellows
		colors.add(newColor(255, 195, 77));
		colors.add(newColor(255, 194, 35));
		colors.add(newColor(253, 184, 21));
		colors.add(newColor(252, 175, 23));
		colors.add(newColor(240, 173, 150)); //Reds
		colors.add(newColor(234, 151, 124));
		colors.add(newColor(233, 134, 106));
		colors.add(newColor(231, 116, 87));
		colors.add(newColor(219, 93, 67));
		colors.add(newColor(217, 70, 49));
		colors.add(newColor(214, 25, 33));
		
	}
	
	
	private int newColor(int r, int g, int b) {
		return GLOBAL.processing.color(r, g, b);
	}
	
	private void findMax() {
		maxVal = 0;
		
		for(int x=0; x<12; ++x) {
			for(int y=0; y<7; ++y) {
				for(int z=0; z<24; ++z)  {
					int val = DATA[x][y][z];
					if(val > maxVal)
						maxVal = val;
				}
			}
		}
	}//end findMax()
	
	private int getColor(int value) {
		if(value == 0)
			return defaultColor;
		
		int index = (int) PApplet.map(value, minVal, maxVal, 0, colors.size()-1);		
		
		if(index > 19)
			index = 19;
		
		return colors.get(index);
	}
	
	private String getYearString()
	{
		if(year == 0 || year == 2000)
			return "2005-2009";
		return "" + year;
	}

	//eg. "Sundays in January at 12am
	private String getDateString(int x, int y, int z) {
		return getDayOfWeekString(y) + " in " 
				+ getMonthString(x) + " at "
				+ getTimeString(z);
	}
	
	private String getMonthString(int m) {
		switch (m) {
		case 0: return "January";
		case 1: return "Februrary";
		case 2: return "March";
		case 3: return "April";
		case 4: return "May";
		case 5: return "June";
		case 6: return "July";
		case 7: return "August";
		case 8: return "September";
		case 9: return "October";
		case 10: return "November";
		case 11: return "December";
		default: return "";
		}	
	}
	
	private String getDayOfWeekString(int d) {
		switch(d) {
		case 0:	return "Sundays";
		case 1: return "Mondays";
		case 2: return "Tuesdays";
		case 3: return "Wednesdays";
		case 4: return "Thursdays";
		case 5: return "Fridays";
		case 6: return "Saturdays";
		default: return "";
		}
	}

	private String getTimeString(int t) {
		String amPm = "pm";
		if(t==0) {
			t += 12;
			amPm = "am";
		}
		else if(t>12) {
			t -= 12;
		}
		else {
			amPm = "am";
		}
		
		return "" + t + " " + amPm;
	}
}
